<template>
  <div>
    <!-- 👇 第一块：微表情识别功能 -->
    <div>
      <button @click="toggleRun">{{ running ? '关闭识别' : '开始识别' }}</button>
      <video ref="video" autoplay muted width="300" v-show="running" />

      <div v-if="running" style="margin-top: 10px;">
        <p>当前表情：{{ currentEmotion }}</p>
        <p>已识别时间：{{ duration }} 秒</p>
      </div>

      <div v-show="!running && emotionHistory.length" ref="chart" style="width: 100%; height: 400px; margin-top: 20px;"></div>
    </div>

    <!-- 👇 第二块：语音识别与情感分析功能 -->
    <div class="voice-recorder">
      <h2>语音转写 · 情感与逻辑识别</h2>
      <div class="control-panel">
        <button @click="toggleRecording">{{ buttonText }}</button>
      </div>

      <div class="result-panel" v-html="formattedResult"></div>

      <div v-if="analysisResult" class="analysis-panel">
        <h3>🎯 识别文本：</h3>
        <p>{{ analysisResult.text }}</p>

        <h3>情感分析：</h3>
        <pre>{{ JSON.stringify(analysisResult.sentiment, null, 2) }}</pre>

        <h3>逻辑判断：</h3>
        <p><strong>相似度：</strong>{{ (analysisResult.logic.similarity * 100).toFixed(2) }}%</p>
        <p :style="{ color: analysisResult.logic.flag ? 'red' : 'green' }">
          {{ analysisResult.logic.flag ? '⚠️ ' + analysisResult.logic.message : '✅ ' + (analysisResult.logic.message || '未检测到明显逻辑矛盾。') }}
        </p>
        <div v-if="scoreHistory.length" ref="scoreChart" style="width: 100%; height: 300px; margin-top: 20px;"></div>
      </div>
    </div>
  </div>
</template>


<script>
import * as echarts from 'echarts'
import RecorderManager from 'recorder-manager'; // 假设你有这个录音库
import CryptoJS from 'crypto-js';

export default {
  data() {
    return {
      running: false,
      socket: null,
      currentEmotion: '',
      duration: 0,
      videoStream: null,
      timer: null,
      emotionHistory: [],
      chart: null,
      APPID: 'e9f15e7b',
      API_KEY: '93c94a284b6888c5807546666e22253e',
      recorder: null,
      asrWebSocket: null,
      analysisWebSocket: null,
      analysisWSConnected: false,
      recognitionResult: '',
      tempResult: '',
      isRecording: false,
      isLoading: false,
      connectionStatus: 'CLOSED',
      analysisResult: null,
      scoreHistory: [],
      scoreTimer: null,
      scoreChartInstance: null,
    }
  },
  computed: {
    buttonText() {
      if (this.connectionStatus === 'CONNECTING') return '建立连接中...';
      if (this.connectionStatus === 'OPEN') return '录音中...';
      return '开始录音';
    },
    formattedResult() {
      return (this.recognitionResult || '') + (this.tempResult ? `<span class="temp">${this.tempResult}</span>` : '');
    },
  },
  mounted() {
    this.initRecorder();
    this.initAnalysisWebSocket();
  },
  methods: {
    toggleRun() {
      if (this.running) {
        this.stopRecognition()
      } else {
        this.startRecognition()
      }
    },
    async startRecognition() {
      this.running = true
      this.duration = 0
      this.emotionHistory = []

      await this.startCamera()
      this.startWebsocket()

      this.timer = setInterval(() => {
        this.duration++
        if (this.duration % 30 === 0) {
          this.emotionHistory.push({
            time: `${Math.floor(this.duration / 60)}:${String(this.duration % 60).padStart(2, '0')}`,
            emotion: this.currentEmotion || 'unknown',
          })
        }
      }, 1000)
    },
    stopRecognition() {
      this.running = false
      clearInterval(this.timer)

      if (this.socket) this.socket.close()
      if (this.videoStream) {
        this.videoStream.getTracks().forEach(track => track.stop())
      }

      this.$nextTick(this.drawChart)
    },
    async startCamera() {
      this.videoStream = await navigator.mediaDevices.getUserMedia({ video: true })
      this.$refs.video.srcObject = this.videoStream
    },
    startWebsocket() {
      this.socket = new WebSocket('ws://localhost:8000/ws/emotion')

      this.socket.onopen = () => this.captureFrames()
      this.socket.onmessage = (event) => {
        const data = JSON.parse(event.data)
        if (data.result && data.result[0]) {
          const label = data.result[0].label
          this.currentEmotion = this.translateEmotion(label)
        }
      }
    },
    captureFrames() {
      const video = this.$refs.video
      const canvas = document.createElement('canvas')
      canvas.width = 300
      canvas.height = 300
      const ctx = canvas.getContext('2d')

      const sendFrame = () => {
        if (!this.running || this.socket.readyState !== WebSocket.OPEN) return
        ctx.drawImage(video, 0, 0, 300, 300)
        const frame = canvas.toDataURL('image/jpeg').split(',')[1]
        this.socket.send(JSON.stringify({ frame }))
        setTimeout(sendFrame, 200)
      }

      sendFrame()
    },
    drawChart() {
  const emotionEmojiMap = {
    '严肃': '😠',
    '开心': '😄',
    '悲伤': '😢',
    '中性': '😐',
    '厌恶': '🤢',
    '惊讶': '😲',
    '恐惧': '😨',
    'unknown': '❓'
  }

  const times = this.emotionHistory.map(item => item.time)
  const emotions = this.emotionHistory.map(item => item.emotion)

  this.chart = echarts.init(this.$refs.chart)
  this.chart.setOption({
    title: {
      text: '识别时长与表情变化',
    },
    tooltip: {
      trigger: 'axis',
      formatter: (params) => {
        const emotion = params[0].data
        return `时间：${params[0].axisValue}<br/>表情：${emotion} ${emotionEmojiMap[emotion] || ''}`
      },
    },
    xAxis: {
      type: 'category',
      data: times,
    },
    yAxis: {
      type: 'category',
      data: [...new Set(emotions)],
    },
    series: [
      {
        name: '表情',
        type: 'line',
        data: emotions,
        label: {
          show: true,
          formatter: (params) => {
            const e = params.value
            return `${emotionEmojiMap[e] || ''} ${e}`
          },
        },
        symbolSize: 18,
      },
    ],
  })
},

    translateEmotion(en) {
      const map = {
        angry: '严肃',
        happy: '开心',
        sad: '悲伤',
        neutral: '中性',
        disgust: '厌恶',
        surprised: '惊讶',
        scared: '恐惧',
      }
      return map[en] || en
    },
    initRecorder() {
      this.recorder = new RecorderManager('/dist');
      this.recorder.onStart = () => {
        this.isRecording = true;
        this.connectionStatus = 'OPEN';
      };
      this.recorder.onStop = () => {
        this.isRecording = false;
      };
      this.recorder.onFrameRecorded = ({ isLastFrame, frameBuffer }) => {
        if (this.asrWebSocket && this.asrWebSocket.readyState === WebSocket.OPEN) {
          this.asrWebSocket.send(new Int8Array(frameBuffer));
          if (isLastFrame) this.asrWebSocket.send(JSON.stringify({ end: true }));
        }
      };
    },
    getAsrUrl() {
      const ts = Math.floor(Date.now() / 1000);
      const signa = CryptoJS.MD5(this.APPID + ts).toString();
      const signature = CryptoJS.HmacSHA1(signa, this.API_KEY).toString(CryptoJS.enc.Base64);
      return `wss://rtasr.xfyun.cn/v1/ws?appid=${this.APPID}&ts=${ts}&signa=${encodeURIComponent(signature)}`;
    },
    connect() {
      this.isLoading = true;
      this.connectionStatus = 'CONNECTING';
      this.recognitionResult = '';
      this.tempResult = '';
      this.analysisResult = null;
      this.scoreHistory = [];
      this.startScoreTimer();


      // 建立ASR连接
      this.asrWebSocket = new WebSocket(this.getAsrUrl());
      this.asrWebSocket.binaryType = 'arraybuffer';

      this.asrWebSocket.onopen = () => {
        this.isLoading = false;
        this.recorder.start({ sampleRate: 16000, frameSize: 1280 });
      };
      this.asrWebSocket.onmessage = e => this.handleAsrMessage(e.data);
      this.asrWebSocket.onerror = () => {
        this.recognitionResult += `<p class="error">ASR 连接错误，请重试</p>`;
        this.disconnect();
      };
      this.asrWebSocket.onclose = () => this.disconnect();
    },
    disconnect() {
      this.isRecording = false;
      this.isLoading = false;
      this.connectionStatus = 'CLOSED';
      this.recorder.stop();
      if (this.asrWebSocket) this.asrWebSocket.close();
      this.asrWebSocket = null;
      this.cleanupAnalysisWS();
      if (this.scoreTimer) {
        clearInterval(this.scoreTimer);
        this.scoreTimer = null;
      };
    },
    handleAsrMessage(msg) {
      const j = JSON.parse(msg);
      if (j.action === 'result') {
        const dt = JSON.parse(j.data);
        let text = '';
        dt.cn.st.rt.forEach(rt =>
          rt.ws.forEach(ws =>
            ws.cw.forEach(c => (text += c.w))
          )
        );
        if (dt.cn.st.type == 0) {
          this.recognitionResult += text;
          this.tempResult = '';
          // 发送给分析WebSocket
          this.sendTextForAnalysis(this.recognitionResult);
        } else {
          this.tempResult = text;
        }
      }
    },
    startScoreTimer() {
      this.scoreTimer = setInterval(() => {
        if (
          this.analysisResult &&
          this.analysisResult.sentiment &&
          this.analysisResult.sentiment.length > 0
        ) {
          const score = this.analysisResult.sentiment[0].score;
          const timestamp = (this.scoreHistory.length + 1).toString();
          this.scoreHistory.push({ time: timestamp, score });

          this.updateScoreChart();
        }
      }, 1000); // 每秒记录一次
    },


    // 分析WebSocket相关
    initAnalysisWebSocket() {
      this.analysisWebSocket = new WebSocket("ws://localhost:8000/ws/asr_emotion_logic");
      this.analysisWebSocket.onopen = () => {
        this.analysisWSConnected = true;
        console.log("分析 WebSocket 已连接");
      };
      this.analysisWebSocket.onmessage = e => {
        try {
          this.analysisResult = JSON.parse(e.data);
          console.log("分析结果：", this.analysisResult);
        } catch {
          this.analysisResult = {
            text: '',
            sentiment: '解析失败',
            logic: { similarity: 0, flag: false, message: '返回异常' },
          };
        }
      };
      this.analysisWebSocket.onerror = () => {
        this.analysisResult = {
          text: '',
          sentiment: '分析服务失败',
          logic: { similarity: 0, flag: false, message: '' },
        };
      };
      this.analysisWebSocket.onclose = () => {
        this.analysisWSConnected = false;
        console.log("分析 WebSocket 已关闭");
      };
    },

    sendTextForAnalysis(text) {
      if (this.analysisWSConnected && this.analysisWebSocket.readyState === WebSocket.OPEN) {
        this.analysisWebSocket.send(JSON.stringify({ text }));
        console.log("发送文本给分析服务:", text);
      } else {
        console.warn("分析 WebSocket 未连接，无法发送文本");
      }
    },

    cleanupAnalysisWS() {
      if (this.analysisWebSocket && this.analysisWebSocket.readyState === WebSocket.OPEN) {
        this.analysisWebSocket.close();
      }
      this.analysisWebSocket = null;
      this.analysisWSConnected = false;
    },

    toggleRecording() {
      if (this.connectionStatus === 'CLOSED') {
        this.connect();
      } else {
        this.disconnect();
      }
    },
    updateScoreChart() {
      if (!this.$refs.scoreChart) return;
      if (!this.scoreChartInstance) {
        this.scoreChartInstance = echarts.init(this.$refs.scoreChart);
      }

      const times = this.scoreHistory.map(item => item.time);
      const scores = this.scoreHistory.map(item => item.score);

      this.scoreChartInstance.setOption({
        title: { text: '情感得分实时变化' },
        xAxis: { type: 'category', data: times },
        yAxis: { type: 'value', min: 0, max: 1 },
        series: [
          {
            data: scores,
            type: 'line',
            smooth: true,
            areaStyle: {},
            label: {
              show: true,
              formatter: (v) => (v.value * 100).toFixed(1),
            },
          },
        ],
        tooltip: {
          trigger: 'axis',
          formatter: (params) => {
            const p = params[0];
            return `时间：${p.axisValue}<br>得分：${(p.data * 100).toFixed(1)}`;
          },
        },
      });
    },
  },
  beforeDestroy() {
    this.stopRecognition();
    this.disconnect();
    this.cleanupAnalysisWS();
  },
}
</script>
